using UnityEngine;
using System.Collections;

namespace CameraControl
{
	[AddComponentMenu("MouseOrbitImproved")]

	/// <summary>
	/// Mouse orbit improved.
	/// </summary>
	public class MouseOrbitImproved : MonoBehaviour
	{
		public Transform target;
		public float distance = 10.0f;
	
		public float xSpeed = 250.0f;
		public float ySpeed = 120.0f;
	
		public float yMinLimit = -20f;
		public float yMaxLimit = 80f;

		public float distanceMin = 0.5f;
		public float distanceMax = 15.0f;
	
		private float x = 0.0f;
		private float y = 0.0f;
		private bool rotate = false;
		
		void Start ()
		{
			//Set angles to the camera's current rotation
			Vector3 angles = transform.eulerAngles;
			x = angles.y;
			y = angles.x;
		
			// Make the rigid body not change rotation
			if (rigidbody) {
				rigidbody.freezeRotation = true;
			}
		}

		void Update ()
		{
			//Rotate camera key
			if (Input.GetMouseButton (1)) {
				rotate = true;
			} else {
				rotate = false;
			}
		}

		void LateUpdate ()
		{
			if (target) {
				//Mouse X and Y rotation for the camera
				if (rotate == true) {
					x += Input.GetAxis ("Mouse X") * xSpeed * Time.deltaTime;
					y -= Input.GetAxis ("Mouse Y") * ySpeed * Time.deltaTime;
				}

				//Stops the camera from going over or under the limits on the y axis
				y = ClampAngle (y, yMinLimit, yMaxLimit);

				//new quaternion which can be used for the camera's rotation
				Quaternion rotation = Quaternion.Euler (y, x, 0);

				//Stops the camera from going over or under the limits of its zoom
				distance = Mathf.Clamp (distance - Input.GetAxis ("Mouse ScrollWheel") * 5, distanceMin, distanceMax);

				RaycastHit snapHit;

				//Used if the target is obstructed from the camera view
				if (Physics.Linecast (target.position, transform.position, out snapHit)) {
					//Adjusts the camera's distance to the hit distance so it is not obstucted
					distance -= snapHit.distance;
				}

				//negDistance is used to adjust the distance of the camera from the target
				Vector3 negDistance = new Vector3 (0.0f, 0.0f, -distance);
				Vector3 position = rotation * negDistance + target.position;

				//Move and rotate camera
				transform.rotation = rotation;
				transform.position = position;

				//Rotate target
				target.transform.rotation = Quaternion.Euler (0.0f, x, 0.0f);
			}
		}

		//Makes the camera rotation relative to 360 degrees on any axis
		/// <summary>
		/// Clamps the angle.
		/// </summary>
		/// <returns>The angle.</returns>
		/// <param name="angle">Angle.</param>
		/// <param name="min">Minimum.</param>
		/// <param name="max">Max.</param>
		static float ClampAngle (float angle, float min, float max)
		{
			if (angle < -360) {
				angle += 360;
			}

			if (angle > 360) {
				angle -= 360;
			}

			return Mathf.Clamp (angle, min, max);
		}
	}
}
